﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using ReportWizard.Comparers;
using ReportWizard.Helpers;
using ReportWizard.Properties;
using SortOrder = System.Windows.Forms.SortOrder;

namespace ReportWizard.DataAccess
{
    public class UserInfo
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Login { get; set; }
        public string FullInfo { get; private set; }
        public string Password { get; set; }
        public DateTime DateCreated { get; set; }
        public bool Admin { get; set; }
        public bool Active { get; set; }
        public bool Visible { get; set; }
        public bool Deleted { get; set; }

        public enum SortingFields
        {
            FirstName,
            LastName,
            Login,
            DateCreated,
            Admin,
            Active
        }

        public void Insert()
        {
            try
            {
                if (!IsExist())
                {
                    using (SqlConnection con = CommonDb.GetOilWizardConection())
                    {

                        SqlCommand saveCmd = new SqlCommand("UserInfoInsert", con);
                        saveCmd.CommandType = CommandType.StoredProcedure;

                        saveCmd.Parameters.Add("@FirstName", SqlDbType.VarBinary).Value = Crypto.Encrypt(FirstName);
                        saveCmd.Parameters.Add("@LastName", SqlDbType.VarBinary).Value = Crypto.Encrypt(LastName);
                        saveCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);
                        saveCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Crypto.GetMd5Sum(Password));
                        saveCmd.Parameters.Add("@Admin", SqlDbType.Bit).Value = Admin;
                        saveCmd.Parameters.Add("@Active", SqlDbType.Bit).Value = Active;

                        saveCmd.Parameters.Add("@Id", SqlDbType.Int).Direction = ParameterDirection.Output;

                        con.Open();
                        
                        bool isRowsAffected = saveCmd.ExecuteNonQuery() > 0;
                        if (isRowsAffected)
                        {
                            Id = Convert.ToInt32(saveCmd.Parameters["@Id"].Value);

                            HistoryRecord hr = new HistoryRecord
                            {
                                Action = HistoryEvent.UserAdd,
                                Description =
                                    string.Format("{0} {1}/{2} {3} [admin:{4}, active:{5}]", Resources.AddedNewUser, Login, FirstName, LastName, Admin, Active)
                            };
                            hr.Insert();
                            hr.Insert(Id);
                        }
                    }
                }
                else
                {
                    ShowMessage.Error(Resources.SelectedLoginIsExist);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
            }
        }

        public bool Update()
        {
            try
            {
                Password = !Password.Equals(Select(Id).Password)
                               ? Crypto.GetMd5Sum(Password)
                               : Password;

                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand updCmd = new SqlCommand("UserInfoUpdate", con);
                    updCmd.CommandType = CommandType.StoredProcedure;

                    updCmd.Parameters.Add("@Id", SqlDbType.Int).Value = Id;
                    updCmd.Parameters.Add("@FirstName", SqlDbType.VarBinary).Value = Crypto.Encrypt(FirstName);
                    updCmd.Parameters.Add("@LastName", SqlDbType.VarBinary).Value = Crypto.Encrypt(LastName);
                    updCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Password);
                    updCmd.Parameters.Add("@Admin", SqlDbType.Bit).Value = Admin;
                    updCmd.Parameters.Add("@Active", SqlDbType.Bit).Value = Active;

                    con.Open();
                    bool isRowsAffected = updCmd.ExecuteNonQuery() > 0;
                    if (isRowsAffected)
                    {
                        HistoryRecord hr = new HistoryRecord
                        {
                            Action = HistoryEvent.UserChange,
                            Description =
                                string.Format("{0} {1}/{2} {3} [admin:{4}, active:{5}]", Resources.UserProfileUpdated, Login, FirstName, LastName, Admin, Active)
                        };
                        hr.Insert();
                    }
                    return isRowsAffected;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static bool Delete(int id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand delCmd = new SqlCommand("UserInfoDelete", con);
                    delCmd.CommandType = CommandType.StoredProcedure;

                    delCmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;

                    con.Open();
                    bool isRowsAffected = delCmd.ExecuteNonQuery() > 0;
                    if (isRowsAffected)
                    {
                        UserInfo ui = Select(id);
                        if (ui != null)
                        {
                            HistoryRecord hr = new HistoryRecord
                                                   {
                                                       Action = HistoryEvent.UserRemove,
                                                       Description =
                                                           string.Format(
                                                               "{0} {1}/{2} {3} [admin:{4}, active:{5}]",
                                                               Resources.UserProfileDeleted, ui.Login, ui.FirstName, ui.LastName, ui.Admin, ui.Active)
                                                   };
                            hr.Insert();
                        }
                    }
                    return isRowsAffected;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static UserInfo Select(int id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoSelectById", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;

                    con.Open();
                    List<UserInfo> cList = MapFrom(getCmd.ExecuteReader());

                    if (cList != null)
                    {
                        return cList.FirstOrDefault();
                    }
                    return null;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public static UserInfo Select(string login)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoSelectByLogin", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(login);

                    con.Open();
                    List<UserInfo> cList = MapFrom(getCmd.ExecuteReader());

                    if (cList != null)
                    {
                        return cList.FirstOrDefault();
                    }
                    return null;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public static List<UserInfo> Select()
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoSelectAll", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    con.Open();
                    return MapFrom(getCmd.ExecuteReader());
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public static int UserLogin(string userLogin, string userPassword)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoLogin", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(userLogin);
                    getCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Crypto.GetMd5Sum(userPassword));

                    con.Open();

                    object userIdObj = getCmd.ExecuteScalar();
                    if (userIdObj != null && userIdObj != DBNull.Value)
                    {
                        return Convert.ToInt32(userIdObj);
                    }
                    else
                    {
                        HistoryRecord hr = new HistoryRecord
                        {
                            Action = HistoryEvent.Login,
                            Description =
                                string.Format("{0} {1}",Resources.LoginFailed, userLogin)
                        };
                        hr.Insert();

                        return 0;
                    }

                    
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return 0;
            }
        }

        public static bool CreateDefaultUser()
        {
            UserInfo ui = new UserInfo
                              {
                                  FirstName = "-",
                                  LastName = "-",
                                  Login = ConfigReader.DefaultUser,
                                  Password = ConfigReader.DefaultUser,
                                  Visible = true,
                                  Admin = true,
                                  Active = true
                              };

            ui.Insert();

            return ui.Id != 0;
        }

        public static bool IsDefaultUserExist()
        {
            return Select(ConfigReader.DefaultUser) != null;
        }

        private bool IsExist()
        {
            try
            {
                using (SqlConnection con = CommonDb.GetOilWizardConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoIsExist", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);

                    con.Open();
                    return Convert.ToInt32(getCmd.ExecuteScalar()) > 0;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return true;
            }
        }

        private static List<UserInfo> MapFrom(SqlDataReader dr)
        {
            try
            {
                if (dr != null && dr.HasRows)
                {
                    List<UserInfo> acList = new List<UserInfo>();
                    while (dr.Read())
                    {
                        UserInfo wt = new UserInfo
                        {
                            Id = Convert.ToInt32(dr["Id"]),
                            FirstName = Crypto.Decrypt((byte[])dr["FirstName"]),
                            LastName = Crypto.Decrypt((byte[])dr["LastName"]),
                            Login = Crypto.Decrypt((byte[])dr["Login"]),
                            Password = Crypto.Decrypt((byte[])dr["Password"]),
                            DateCreated = Convert.ToDateTime(dr["DateCreated"]),
                            Admin = Convert.ToBoolean(dr["Admin"]),
                            Active = Convert.ToBoolean(dr["Active"]),
                            Visible = Convert.ToBoolean(dr["Visible"]),
                            Deleted = Convert.ToBoolean(dr["Deleted"]),
                        };

                        wt.FullInfo = string.Format("{0} ( {1} {2} )", wt.Login, wt.FirstName, wt.LastName);

                        acList.Add(wt);
                    }
                    acList.Sort(new UserInfoComparer(SortingFields.Login, SortOrder.Ascending));
                    return acList;
                }
                return null;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public override string ToString()
        {
            return String.Format("{0} {1}", FirstName, LastName);
        }
    }
}
